#include "SocketHeader.hpp"
#include <iostream>
#include <string>
#include <string.h>

bool RecvAll(int &sock, char*buffer, int size)
{
    while (size>0)//剩余部分大于0
    {
        int RecvSize= recv(sock, buffer, size, 0);
        if(RecvSize < 0)
        {
            std::cout<<"接收失败"<<std::endl;
            return false;
        }
        size = size - RecvSize;
        buffer+=RecvSize;
    }
    return true;
}

int main(void)
{
    /* 创建套接字接口 */
    int s_streamOut,s_streamIn,s_cmd;

    s_streamOut = socket(AF_INET, SOCK_STREAM, 0);  
    s_streamIn = socket(AF_INET, SOCK_STREAM, 0);  
    s_cmd = socket(AF_INET, SOCK_STREAM, 0);   
    if(s_streamOut < 0 || s_streamIn < 0 || s_cmd < 0)
    {
        std::cerr<<"接收失败"<<std::endl;
        return -1;
    }
    std::cout<<"套接字创建成功"<<std::endl;

    /* 返回值暂存 */
    int res_streamOut,res_streamIn,res_cmd;

    /* 套接字接口配置 */
    struct sockaddr_in sockAddrConfig;
    sockAddrConfig.sin_family = AF_INET;
    sockAddrConfig.sin_addr.s_addr = htonl(INADDR_ANY);

    sockAddrConfig.sin_port = htons(8010);  // Out方向是嵌入式板
    res_streamOut = bind(s_streamOut, (struct sockaddr*)&sockAddrConfig, sizeof(sockAddrConfig));
    
    sockAddrConfig.sin_port = htons(8011);  // In方向是远程客户端
    res_streamIn = bind(s_streamIn, (struct sockaddr*)&sockAddrConfig, sizeof(sockAddrConfig));
    
    sockAddrConfig.sin_port = htons(8012);  // Cmd是通用的
    res_cmd = bind(s_cmd, (struct sockaddr*)&sockAddrConfig, sizeof(sockAddrConfig));
    if(res_streamOut < 0 || res_streamIn < 0 || res_cmd < 0)
    {
        std::cerr<< "bind error"<<std::endl;
        return -2;
    }
    std::cout<<"套接字配置成功"<<std::endl;

    /* TCP监听启动 */
    res_streamOut = listen(s_streamOut,1);
    res_streamIn = listen(s_streamIn,1);
    res_cmd = listen(s_cmd,2);
    if(res_streamOut < 0 || res_streamIn < 0 || res_cmd < 0)
    {
        std::cerr<< "listen error"<<std::endl;
        return -3;
    }
    std::cout<<"监听启动成功"<<std::endl;

    /* 开始连接 */
    std::cout<<"进入连接建立模式"<<std::endl;
    int s_ac_streamOut,s_ac_cmdOut,s_ac_streamIn,s_ac_cmdIn;
    struct sockaddr streamInAddr;   // 对等主机地址
    struct sockaddr streamOutAddr;
    struct sockaddr cmdInAddr,cmdOutAddr;
    socklen_t sockAddrLen = sizeof(sockaddr);
    char buffer_cmd[4];
    for(;;) // 循环等待TCP连接
    {
        // 先收嵌入式板连接
        std::cout<<"等待嵌入式板子连接请求"<<std::endl;
        s_ac_streamOut = accept(s_streamOut, &streamOutAddr, &sockAddrLen);
        if(s_ac_streamOut < 0)
        {
            std::cout<<"嵌入式板子流连接错误"<<std::endl;
            return -1;
            continue;
        }
        std::cout<<"收到来自（"
            <<inet_ntoa(((sockaddr_in *)&streamOutAddr)->sin_addr)<<":"
            <<ntohs(((sockaddr_in *)&streamOutAddr)->sin_port)<<"）的数据连接"<<std::endl;
        
        std::cout<<"收到请求"<<std::endl;
        // 命令校验
        s_ac_cmdOut = accept(s_cmd, &cmdOutAddr, &sockAddrLen);
        if(s_ac_cmdOut < 0)
        {
            std::cout<<"嵌入式板子命令连接错误"<<std::endl;
            close(s_ac_cmdOut);
            close(s_ac_streamOut);
            return -1;
            continue;
        }
        std::cout<<"收到来自（"
            <<inet_ntoa(((sockaddr_in*)&cmdOutAddr)->sin_addr)<<":"
            <<ntohs(((sockaddr_in*)&cmdOutAddr)->sin_port)<<"）的命令连接"<<std::endl;
        std::cout<<"开始进行设备类型校验"<<std::endl;
        
        if(!RecvAll(s_ac_cmdOut,buffer_cmd,4))
        {
            return -1;
        }
        if(strcmp(buffer_cmd,"Emb") != 0)
        {
            // 连接的不是嵌入式板子，口令不对
            close(s_ac_cmdOut);
            close(s_streamOut); 
            std::cout<<"收到的口令:"<<buffer_cmd<<std::endl;
            std::cout<<"非嵌入式板子尝试连接"<<std::endl;
            return -1;
            continue;
        }
        std::cout<<"连接成功"<<std::endl;
        break;
    }
    /**
     * 再收远程客户端连接
     */
    for(;;) // 循环等待TCP连接
    {
        std::cout<<"等待客户端连接请求"<<std::endl;
        s_ac_streamIn = accept(s_streamIn, &streamInAddr, &sockAddrLen);
        if(s_ac_streamIn < 0)
        {
            std::cout<<"客户端流连接错误"<<std::endl;
            return -1;
            continue;
        }
        std::cout<<"收到来自（"
            <<inet_ntoa(((sockaddr_in *)&streamInAddr)->sin_addr)<<":"
            <<ntohs(((sockaddr_in *)&streamInAddr)->sin_port)<<"）的数据连接"<<std::endl;
        
        std::cout<<"收到请求"<<std::endl;
        // 命令校验
        s_ac_cmdIn = accept(s_cmd, &cmdInAddr, &sockAddrLen);
        if(s_ac_cmdIn < 0)
        {
            std::cout<<"客户端命令连接错误"<<std::endl;
            close(s_ac_cmdIn);
            close(s_ac_streamIn);
            return -1;
            continue;
        }
        std::cout<<"收到来自（"
            <<inet_ntoa(((sockaddr_in*)&cmdInAddr)->sin_addr)<<":"
            <<ntohs(((sockaddr_in*)&cmdInAddr)->sin_port)<<"）的命令连接"<<std::endl;
        std::cout<<"开始进行设备类型校验"<<std::endl;
        
        if(!RecvAll(s_ac_cmdIn,buffer_cmd,4))
        {
            return -1;
        }
        if(strcmp(buffer_cmd,"Cli") != 0)
        {
            // 连接的不是客户端，口令不对
            close(s_ac_cmdIn);
            close(s_streamIn); 
            std::cout<<"收到的口令:"<<buffer_cmd<<std::endl;
            std::cout<<"非嵌入式板子尝试连接"<<std::endl;
            return -1;
            continue;
        }
        std::cout<<"连接成功"<<std::endl;
        break;
    }
    std::cout<<"连接建立成功"<<std::endl
        <<"开始数据传输"<<std::endl;

    /* 数据转发 */
    unsigned char dataBuffer[TCP_PACK_MAX_SIZE];
    int transmitSize;
    while(1)
    {
        res_cmd = recv(s_ac_cmdIn,&transmitSize,sizeof(transmitSize),0);
        if(res_cmd <=0)
        {
            std::cerr<<"接收转发数据长度失败"<<std::endl;
            // return -5;
            break;
        }
        std::cout<<"开始转发"<<transmitSize<<"长度的数据包"<<std::endl;

        for(int _i = transmitSize / TCP_PACK_MAX_SIZE; _i>0; _i--)
        {
            res_streamIn = recv(s_ac_streamIn,
                    &dataBuffer,TCP_PACK_MAX_SIZE,0);
            if(res_streamIn <= 0)
            {
                std::cerr<< "recv error"<<std::endl;
                // return -5;
            break;
            }
            res_streamOut = send(s_ac_streamOut,
                    &dataBuffer,TCP_PACK_MAX_SIZE,0);
            if(res_streamOut <= 0)
            {
                std::cerr<< "send error"<<std::endl;
                // return -5;
            break;
            }
            std::cout<<"转发一个大包,还有"<<_i<<"个包"<<std::endl;
        }

        res_streamIn = recv(s_ac_streamIn,
                    &dataBuffer,transmitSize % TCP_PACK_MAX_SIZE,0);
        if(res_streamIn <= 0)
        {
            std::cerr<< "recv error"<<std::endl;
            // return -5;
            break;
        }
        res_streamOut = send(s_ac_streamOut,
                &dataBuffer,transmitSize % TCP_PACK_MAX_SIZE,0);
        if(res_streamOut <= 0)
        {
            std::cerr<< "send error"<<std::endl;
            // return -5;
            break;
        }
        std::cout<<"转发一个包,数据量"<<transmitSize % TCP_PACK_MAX_SIZE<<"字节"<<std::endl;

    }
    close(s_ac_cmdIn);
    close(s_ac_cmdOut);
    close(s_ac_streamIn);
    close(s_ac_streamOut);
    close(s_cmd);
    close(s_streamIn);
    close(s_streamOut);

    return 0;
}